using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using LSO;

namespace lsotool
{
    class lsotool
    {
        static string cmd_infile = "";
        static string cmd_outfile = "";
        static bool cmd_assemble = false;
        static bool cmd_disassemble = false;
        static bool cmd_smaller = false;

        static void Help()
        {
            Console.WriteLine("lsotool infile outfile -option1 -option2 ...");
            Console.WriteLine("-h     Help");
            Console.WriteLine("-a     Assemble");
            Console.WriteLine("-d     Disassemble");
            Console.WriteLine("-small Perform size optimizations");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("");

            // Set options from arguments
            foreach (string arg in args)
            {
                if (arg == "-h" || arg == "-?" || arg == "-help")
                    Help();
                else if (arg == "-a" || arg == "-assemble")
                    cmd_assemble = true;
                else if (arg == "-d" || arg == "-disassemble")
                    cmd_disassemble = true;
                else if(arg == "-small" || arg == "-smaller")
                    cmd_smaller = true;
                else
                {
                    if (cmd_infile == "")
                        cmd_infile = arg;
                    else if (cmd_outfile == "")
                        cmd_outfile = arg;
                    else
                    {
                        Help();
                        return;
                    }
                }
            }

            // Must choose one or the other
            if (cmd_assemble == cmd_disassemble)
            {
                if (cmd_smaller == true && cmd_assemble == false && cmd_disassemble == false)
                {
                    // Unless you want to optimize a binary
                }
                else
                {
                    Help();
                    return;
                }
            }

            string text = "";
            LSOAssembly assembly = new LSOAssembly();
            byte[] binary = new byte[0];

            // "In" phase

            if (File.Exists(cmd_infile) == false)
            {
                Console.WriteLine("The file \"" + cmd_infile + "\" was not found.");
                return;
            }

            // Open either text or binary
            if (cmd_assemble == true)
            {
                FileStream instream = File.OpenRead(cmd_infile);
                StreamReader reader = new StreamReader(instream);
                text = reader.ReadToEnd();
                reader.Close();
                instream.Close();

                LSO.LSOAssembler assembler = new LSO.LSOAssembler();
                if (assembler.Assemble(text) == false)
                {
                    Console.WriteLine("Compile error: " + assembler.ErrorMessage);
                    return;
                }
                assembly = assembler.Assembly;
                binary = assembly.Assembled();
            }
            else if (cmd_disassemble == true || cmd_smaller == true)
            {
                FileStream instream = File.OpenRead(cmd_infile);
                BinaryReader reader = new BinaryReader(instream);
                binary = new byte[instream.Length];
                reader.Read(binary, 0, (int)instream.Length);
                reader.Close();
                instream.Close();

                assembly = new LSOAssembly();
                assembly.FromBytes(binary);
                text = assembly.ToString();
            }

            // "Middle" phase

            if (cmd_smaller == true)
            {
                int size_before = assembly.Size;
                assembly = LSOOptimizer.PerformAllOptimizations(assembly);
                binary = assembly.Assembled();
                int size_after = assembly.Size;
                int size_difference = size_before - size_after;
                Console.WriteLine("Optimizations saved " + size_difference.ToString() + " bytes.");
                if (cmd_disassemble == true)
                    text = assembly.ToString();
            }

            // "Out" phase

            // Write either the text or the binary
            if (cmd_assemble == true || (cmd_smaller == true && cmd_disassemble == false))
            {
                FileStream outstream = File.OpenWrite(cmd_outfile);
                BinaryWriter writer = new BinaryWriter(outstream);
                outstream.Write(binary, 0, binary.Length);
                writer.Close();
                outstream.Close();
            }
            else if (cmd_disassemble == true)
            {
                FileStream outstream = File.OpenWrite(cmd_outfile);
                StreamWriter writer = new StreamWriter(outstream);
                writer.Write(text);
                writer.Close();
                outstream.Close();
            }
        }
    }
}
